package com.atguigu05.communication;

/**
 * ClassName: ProducerConsumerTest
 * Package: com.atguigu05.communication
 * Description:
 *         案例2:生产者&消费者
 *         生产者(Productor)将产品交给店员(Clerk)，而消费者(Customer)从店员处取走产品，
 *         店员一次只能持有固定数量的产品(比如:20)，如果生产者试图生产更多的产品，店员会叫生产者停一下，
 *         如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了，店员会告诉消费者等一下，
 *         如果店中有产品了再通知消费者来取走产品。
 *
 *          分析：
 *          1.多线程：生产者、消费者
 *          2.共享数据：产品数量
 *          3.线程安全：有共享数据
 *          4.要使用同步机制解决线程安全
 *          5.线程通信：生产者、消费者
 * @Author ZY
 * @Create 15:31
 * @Version 1.0
 */

class Clerk {//店员

    private int productNum = 0;//产品数量

    //增加产品数量方法
    public synchronized void addProduct() {

        if(productNum >= 20){
            //等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        productNum++;
        System.out.println(Thread.currentThread().getName() + "生产了第" + productNum + "个产品");

        //唤醒
        notify();
    }

    //减少产品数量方法
    public synchronized void minusProduct() {
        if(productNum <= 0){
            //等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + "消费了第" + productNum + "个产品");
        productNum--;

        //唤醒
        notify();
    }


}

class Producer extends Thread{//生产者

    private Clerk clerk;
    public Producer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while(true){
            System.out.println("生产者开始生产产品...");

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.addProduct();
        }
    }
}

class Consumer extends Thread{//消费者

    private Clerk clerk;
    public Consumer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while(true){
            System.out.println("消费者开始消费产品...");

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.minusProduct();
        }

    }
}


public class ProducerConsumerTest {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Producer p1 = new Producer(clerk);
        Consumer c1 = new Consumer(clerk);

        p1.setName("生产者1");
        c1.setName("消费者1");

        p1.start();
        c1.start();

    }
}
